/**
 * This file is part of 1genia trampoline
 * Copyright (C) 2007-2008 1genia (contact@1genia.com)
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; version 3 of the License. 
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details. 
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; see the file COPYING.TXT.  If not,
 * write to the Free Software Foundation, Inc., 51 Franklin Street,
 * Fifth Floor, Boston, MA 02110-1301, USA. 
 **/
package com.genia.toolbox.basics.manager.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.List;

import com.Ostermiller.util.CSVParse;
import com.Ostermiller.util.CSVParser;
import com.Ostermiller.util.CSVPrint;
import com.Ostermiller.util.CSVPrinter;
import com.Ostermiller.util.ExcelCSVParser;
import com.Ostermiller.util.ExcelCSVPrinter;
import com.genia.toolbox.basics.bean.CsvConfiguration;
import com.genia.toolbox.basics.bean.InputStreamFactory;
import com.genia.toolbox.basics.bean.MutableCsvConfiguration;
import com.genia.toolbox.basics.bean.impl.CsvConfigurationImpl;
import com.genia.toolbox.basics.exception.technical.TechnicalException;
import com.genia.toolbox.basics.manager.CsvManager;
import com.genia.toolbox.basics.manager.ExceptionManager;
import com.genia.toolbox.basics.manager.StreamManager;

/**
 * Implementation of {@link CsvManager}.
 */
public class CsvManagerImpl
    implements CsvManager
{

  /**
   * the {@link StreamManager} to use.
   */
  private StreamManager streamManager;

  /**
   * the {@link ExceptionManager} to use.
   */
  private ExceptionManager exceptionManager;



  /**
   * returns the default Cvs configuration.
   * 
   * @return the default Cvs configuration
   * @see com.genia.toolbox.basics.manager.CsvManager#defaultCsvConfiguration()
   */
  public MutableCsvConfiguration defaultCsvConfiguration()
  {
    return new CsvConfigurationImpl();
  }



  /**
   * parse a csv File.
   * 
   * @param input
   *          the file to parse
   * @return the lines of the cvs file
   * @throws TechnicalException
   *           if an error occured
   * @see CsvManager#parseCsv(InputStream)
   */
  public String[][] parseCsv(InputStream input)
      throws TechnicalException
  {
    return parseCsv(defaultCsvConfiguration(), input);
  }



  /**
   * parse a csv File.
   * 
   * @param configuration
   *          the configuration to use for the parsing
   * @param input
   *          the file to parse
   * @return the lines of the cvs file
   * @throws TechnicalException
   *           if an error occured
   * @see CsvManager#parseCsv(CsvConfiguration, InputStream)
   */
  public String[][] parseCsv(CsvConfiguration configuration, InputStream input)
      throws TechnicalException
  {
    try {
      CSVParse csvParse = null;
      InputStream finalInputStream = input;
      String charset = configuration.getEncoding();
      if (charset == null) {
        InputStreamFactory inputStreamFactory = getStreamManager().cloneInputStream(input);
        charset = getStreamManager().getCharset(inputStreamFactory.getInputStream());
        finalInputStream = inputStreamFactory.getInputStream();
      }
      final Reader reader = new InputStreamReader(finalInputStream, charset);
      switch (configuration.getCvsType()) {
        case DEFAULT:
          csvParse = new CSVParser(reader, configuration.getDelimiter());
          if (configuration.getCommentDelimiter() != null) {
            ((CSVParser) csvParse).setCommentStart(String.valueOf(configuration.getCommentDelimiter()));
          }
          break;
        case EXCEL:
          csvParse = new ExcelCSVParser(reader, configuration.getDelimiter());
          if (configuration.getCommentDelimiter() != null) {
            ((ExcelCSVParser) csvParse).setCommentStart(String.valueOf(configuration.getCommentDelimiter()));
          }
          break;
      }
      return csvParse.getAllValues();
    }
    catch (Exception e) {
      throw getExceptionManager().convertException(e);
    }
  }



  /**
   * parse a csv File.
   * 
   * @param configuration
   *          the configuration to use for the parsing
   * @param csvFile
   *          the file to parse
   * @return the lines of the cvs file
   * @throws TechnicalException
   *           if an error occured
   * @see com.genia.toolbox.basics.manager.CsvManager#parseCsv(com.genia.toolbox.basics.bean.CsvConfiguration,
   *      java.io.File)
   */
  public String[][] parseCsv(CsvConfiguration configuration, File csvFile)
      throws TechnicalException
  {
    FileInputStream fileInputStream = null;
    try {
      fileInputStream = new FileInputStream(csvFile);
    }
    catch (Exception e) {
      throw getExceptionManager().convertException(e);
    }
    return parseCsv(configuration, fileInputStream);
  }



  /**
   * parse a csv File.
   * 
   * @param csvFile
   *          the file to parse
   * @return the lines of the cvs file
   * @throws TechnicalException
   *           if an error occured
   * @see com.genia.toolbox.basics.manager.CsvManager#parseCsv(java.io.File)
   */
  public String[][] parseCsv(File csvFile)
      throws TechnicalException
  {
    return parseCsv(defaultCsvConfiguration(), csvFile);
  }



  /**
   * print a csv file.
   * 
   * @param configuration
   *          the configuration to use for writing
   * @param comments
   *          the comments to print or <code>null</code> if no comment must be
   *          print
   * @param data
   *          the datas to print
   * @param output
   *          the output to print to
   * @throws TechnicalException
   *           if an error occured
   * @see com.genia.toolbox.basics.manager.CsvManager#printCsv(com.genia.toolbox.basics.bean.CsvConfiguration,
   *      java.util.List, java.util.List, java.io.OutputStream)
   */
  public void printCsv(CsvConfiguration configuration, List<String> comments, List<String[]> data, OutputStream output)
      throws TechnicalException
  {
    try {
      CSVPrint csvPrint = null;
      final String charset = configuration.getEncoding();
      final Writer writer = new OutputStreamWriter(output, charset == null ? com.genia.toolbox.constants.client.Charset.UTF8 : charset);
      switch (configuration.getCvsType()) {
        case DEFAULT:
          csvPrint = new CSVPrinter(writer);
          break;
        case EXCEL:
          csvPrint = new ExcelCSVPrinter(writer);
          break;
      }
      csvPrint.changeDelimiter(configuration.getDelimiter());
      if (configuration.getCommentDelimiter() != null && comments != null) {
        for (String comment : comments) {
          writer.write(configuration.getCommentDelimiter());
          writer.write(' ');
          writer.write(comment);
          csvPrint.writeln();
        }
      }
      for (String[] line : data) {
        csvPrint.println(line);
      }
      csvPrint.close();
    }
    catch (Exception e) {
      throw getExceptionManager().convertException(e);
    }
  }



  /**
   * print a csv file.
   * 
   * @param comments
   *          the comments to print or <code>null</code> if no comment must be
   *          print
   * @param data
   *          the datas to print
   * @param output
   *          the output to print to
   * @throws TechnicalException
   *           if an error occured
   * @see com.genia.toolbox.basics.manager.CsvManager#printCsv(java.util.List,
   *      java.util.List, java.io.OutputStream)
   */
  public void printCsv(List<String> comments, List<String[]> data, OutputStream output)
      throws TechnicalException
  {
    printCsv(defaultCsvConfiguration(), comments, data, output);
  }



  /**
   * getter for the streamManager property.
   * 
   * @return the streamManager
   */
  public StreamManager getStreamManager()
  {
    return streamManager;
  }



  /**
   * setter for the streamManager property.
   * 
   * @param streamManager
   *          the streamManager to set
   */
  public void setStreamManager(StreamManager streamManager)
  {
    this.streamManager = streamManager;
  }



  /**
   * getter for the exceptionManager property.
   * 
   * @return the exceptionManager
   */
  public ExceptionManager getExceptionManager()
  {
    return exceptionManager;
  }



  /**
   * setter for the exceptionManager property.
   * 
   * @param exceptionManager
   *          the exceptionManager to set
   */
  public void setExceptionManager(ExceptionManager exceptionManager)
  {
    this.exceptionManager = exceptionManager;
  }

}
